package com.example.limit.rule;

import com.example.limit.entity.PurchaseRule;
import com.example.limit.mapper.PurchaseRuleMapper;
import com.example.limit.service.RedisCounterService;
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.api.RulesEngine;
import org.jeasy.rules.api.RulesEngineParameters;
import org.jeasy.rules.core.DefaultRulesEngine;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 增强的购买规则引擎 - 集成Redis计数和分布式锁
 */
@Service
public class EnhancedPurchaseRuleEngine {
    
    private final PurchaseRuleMapper ruleMapper;
    private final RedisCounterService counterService;
    private final RedissonClient redissonClient;
    private final RulesEngine rulesEngine;
    
    public EnhancedPurchaseRuleEngine(PurchaseRuleMapper ruleMapper, 
                                    RedisCounterService counterService,
                                    RedissonClient redissonClient) {
        this.ruleMapper = ruleMapper;
        this.counterService = counterService;
        this.redissonClient = redissonClient;
        
        // 配置规则引擎参数
        RulesEngineParameters parameters = new RulesEngineParameters()
            .skipOnFirstAppliedRule(false)
            .skipOnFirstFailedRule(false)
            .skipOnFirstNonTriggeredRule(false)
            .priorityThreshold(10);
        
        this.rulesEngine = new DefaultRulesEngine(parameters);
    }
    
    /**
     * 使用分布式锁和规则引擎校验购买限制
     */
    public RuleEngineResult checkPurchaseLimitWithLock(Long userId, String productId, 
                                                      String categoryId, int quantity,
                                                      Map<String, Object> context) {
        
        String lockKey = counterService.generateKey("easyrule:lock", userId.toString(), productId);
        RLock lock = redissonClient.getLock(lockKey);
        
        try {
            if (lock.tryLock(3, 10, TimeUnit.SECONDS)) {
                return executeRuleEngine(userId, productId, categoryId, quantity, context);
            } else {
                return new RuleEngineResult(false, "获取分布式锁失败", Collections.emptyList());
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return new RuleEngineResult(false, "系统繁忙，请重试", Collections.emptyList());
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
    
    private RuleEngineResult executeRuleEngine(Long userId, String productId, 
                                              String categoryId, int quantity,
                                              Map<String, Object> context) {
        
        // 准备事实数据
        Facts facts = prepareFacts(userId, productId, categoryId, quantity, context);
        
        // 加载并注册规则
        Rules rules = loadRedisAwareRules();
        
        // 执行规则引擎
        rulesEngine.fire(rules, facts);
        
        // 收集执行结果
        return collectResults(facts, rules);
    }
    
    private Facts prepareFacts(Long userId, String productId, String categoryId, 
                              int quantity, Map<String, Object> context) {
        Facts facts = new Facts();
        
        Map<String, Object> purchaseContext = new HashMap<>();
        purchaseContext.put("userId", userId);
        purchaseContext.put("productId", productId);
        purchaseContext.put("categoryId", categoryId);
        purchaseContext.put("quantity", quantity);
        purchaseContext.put("purchaseTime", LocalDateTime.now());
        
        if (context != null) {
            purchaseContext.putAll(context);
        }
        
        facts.put("context", purchaseContext);
        facts.put("results", new HashMap<String, Object>());
        
        return facts;
    }
    
    private Rules loadRedisAwareRules() {
        List<PurchaseRule> dbRules = ruleMapper.selectActiveRules();
        Rules rules = new Rules();
        
        for (PurchaseRule dbRule : dbRules) {
            RedisAwareRule rule = new RedisAwareRule(dbRule, counterService);
            
            // 设置优先级
            if (dbRule.getPriority() != null) {
                int easyRulesPriority = 100 - dbRule.getPriority();
                //rule.setPriority(easyRulesPriority);
            }
            
            rules.register(rule);
        }
        
        return rules;
    }
    
    private RuleEngineResult collectResults(Facts facts, Rules rules) {
        Map<String, Object> results = facts.get("results");
        List<RuleExecutionDetail> details = new ArrayList<>();
        
        boolean overallResult = true;
        String message = "所有规则校验通过";
        
        for (org.jeasy.rules.api.Rule rule : rules) {
            String ruleId = extractRuleId(rule.getName());
            boolean ruleTriggered = results.containsKey("rule_" + ruleId);
            boolean rulePassed = ruleTriggered;
            
            RuleExecutionDetail detail = new RuleExecutionDetail(
                Long.parseLong(ruleId),
                rule.getName(),
                rule.getDescription(),
                ruleTriggered,
                rulePassed
            );
            
            details.add(detail);
            
            if (!rulePassed) {
                overallResult = false;
                message = "部分规则校验失败";
            }
        }
        
        details.sort(Comparator.comparing(RuleExecutionDetail::getRuleId));
        
        return new RuleEngineResult(overallResult, message, details);
    }
    
    private String extractRuleId(String ruleName) {
        return ruleName.substring(5);
    }
    
    /**
     * 规则引擎结果
     */
    public static class RuleEngineResult {
        private final boolean passed;
        private final String message;
        private final List<RuleExecutionDetail> ruleDetails;
        
        public RuleEngineResult(boolean passed, String message, List<RuleExecutionDetail> ruleDetails) {
            this.passed = passed;
            this.message = message;
            this.ruleDetails = ruleDetails;
        }
        
        public boolean isPassed() { return passed; }
        public String getMessage() { return message; }
        public List<RuleExecutionDetail> getRuleDetails() { return ruleDetails; }
    }
    
    /**
     * 规则执行详情
     */
    public static class RuleExecutionDetail {
        private final Long ruleId;
        private final String ruleName;
        private final String description;
        private final boolean triggered;
        private final boolean passed;
        
        public RuleExecutionDetail(Long ruleId, String ruleName, String description, 
                                 boolean triggered, boolean passed) {
            this.ruleId = ruleId;
            this.ruleName = ruleName;
            this.description = description;
            this.triggered = triggered;
            this.passed = passed;
        }
        
        public Long getRuleId() { return ruleId; }
        public String getRuleName() { return ruleName; }
        public String getDescription() { return description; }
        public boolean isTriggered() { return triggered; }
        public boolean isPassed() { return passed; }
    }
}